module.exports = {
  env: {
    es6: true,
    node: true,
    browser: true,
    commonjs: true,
  },

  parserOptions: {
    ecmaVersion: 2017,
    sourceType: 'module',
    ecmaFeatures: {impliedStrict: true},
  },

  extends: 'eslint:recommended',
  rules: {
    // Allow use of console.log
    'no-console': 0,

    // Warn when a variable is unused
    'no-unused-vars': 1,

    // Prefer destructuring assignments
    'prefer-destructuring': 1,

    // Disallow `return await p` (use `return p`!)
    'no-return-await': 2,

    // Disallow unused expressions w/o side effects
    'no-unused-expressions': 2,

    // No semicolons, thanks
    'semi': [2, 'never'],

    // Use curly brackets when the block is on a different line to the keyword
    'curly': [2, 'multi-line'],

    // Use separate var statements for each variable
    'one-var': [2, 'never'],

    // Prefer const over let over var
    'no-var': 1,
    'prefer-const': 1,

    // If you do use var, hoist it to the top of the function manually
    'vars-on-top': 2,

    // Disallow backward comparisons eg. `5 > age`
    'yoda': [2, 'never'],

    // Enforce consistent newlines in arrays and objects
    'array-bracket-newline': [2, 'consistent'],
    'object-curly-newline': [2, {consistent: true}],

    // Require a trailing comma on multiline literals, where possible
    'comma-dangle': [2, 'always-multiline'],

    // ESLint doesn't let us enforce different spacing rules for destructured
    // parameters, so the following are disabled. Hopefully a plugin/fix comes
    // for this in the future :)
    'object-curly-spacing': [0, 'never'],
    'array-bracket-spacing': [0, 'never'],

    // Object literal naming
    'quote-props': [1, 'consistent-as-needed'],
    'object-shorthand': [1, 'always', {
      avoidQuotes: true,
      avoidExplicitReturnArrows: true,
    }],

    // String style
    'quotes': [2, 'single', {avoidEscape: true, allowTemplateLiterals: true}],
    'prefer-template': 2,
    'template-curly-spacing': [2, 'never'],
    'no-useless-concat': 2,

    // Use camelCase
    'camelcase': 2,

    // Symbols
    'symbol-description': 1,
    'no-new-symbol': 2,

    // Braces on same line as keyword
    'brace-style': [2, '1tbs'],

    // Always use spacing inside one-liner blocks
    'block-spacing': [2, 'always'],

    // Don't use spaces in computed property names
    'computed-property-spacing': [2, 'never'],

    // Enforce 2-space indentation
    'indent': [2, 2, {SwitchCase: 1}],

    // Enforce spacing around blocks and keywords
    'keyword-spacing': 2,
    'switch-colon-spacing': 2,
    'space-before-blocks': 2,

    // Warn where `else if` would be better suited
    'no-lonely-if': 1,

    // Operator style
    'operator-linebreak': [2, 'before'],
    'space-infix-ops': 2,

    // Function style
    'function-paren-newline': [2, 'multiline'],
    'func-style': [2, 'declaration', {allowArrowFunctions: true}],
    'func-call-spacing': [2, 'never'],
    'prefer-rest-params': 2,
    'prefer-spread': 2,
    'space-in-parens': [2, 'never'],

    // Require parens when using `new`
    'new-parens': 2,

    // Arrow function style
    'arrow-body-style': [2, 'as-needed'],
    'arrow-parens': [2, 'as-needed'],
    'arrow-spacing': 2,
    'prefer-arrow-callback': 1,

    // Max line-length of 80, except strings and stuff
    'max-len': [1, {
      code: 80,
      ignoreStrings: true,
      ignoreTemplateLiterals: true,
      ignoreRegExpLiterals: true,
    }],

    // Enforce files end in \n and use unix newlines (\n)
    'eol-last': 2,
    'linebreak-style': 2,
  },
}
